package org.example.classtopia.Service.Impl;

import jakarta.mail.internet.MimeMessage;
import org.example.classtopia.Mapper.UserMapper;
import org.example.classtopia.Model.dto.*;
import org.example.classtopia.Model.vo.*;
import org.example.classtopia.Common.Constant.RedisConstant;
import org.example.classtopia.Service.UserService;
import org.example.classtopia.Model.Entity.User;
import org.example.classtopia.Common.Result.Result;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.bean.BeanUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.example.classtopia.Utils.AliOSSUtils;
import org.example.classtopia.Utils.RegexUtils;
import org.example.classtopia.Utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.util.List;

import static org.example.classtopia.Common.Constant.RedisConstant.LOGIN_EMAIL_KEY;

@Slf4j
@Component
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private AliOSSUtils aliOSSUtils;


    @Value("${spring.mail.username}")
    private String from;

    final int CODE_EXPIRE_MINUTES = 10;
    final int LIMIT_SECONDS = 60;
    @Autowired
    private JavaMailSenderImpl mailSender;

    @Autowired
    private TokenUtils tokenUtils;

    @Override
    public Result Register(RegisterDTO registerDTO, HttpServletRequest request) {
        String email = registerDTO.getEmail();
        String password = registerDTO.getPassword();
        String Code = registerDTO.getCode();

        if(StringUtils.isAnyEmpty(email, password)){
            return Result.error(400,"邮箱和密码不能为空");
        }

        if(password.length() < 6){
            return Result.error(400,"密码长度至少为6位");
        }

        if(!RegexUtils.isEmail(email)){
            return Result.error(400,"邮箱格式不匹配！");
        }

        String CacheCodeKey = RedisConstant.LOGIN_EMAIL_KEY + email;
        String CacheCode = stringRedisTemplate.opsForValue().get(CacheCodeKey);

        if(CacheCode == null)
        {
            return Result.error(400,"验证码未发送或已过期，请重新获取！");
        }

        if(!Code.equals(CacheCode)){
            return Result.error(400,"验证码错误！");
        }
        User getUser = userMapper.FindByEmail(email);

        if(getUser != null){
            return Result.error(400,"该邮箱已被注册");
        }

        User NewUser = new User();
        NewUser.setEmail(email);
        NewUser.setPassword(password);
        NewUser.setIsLogin("N");
        NewUser.setAvatar("https://classtopia-avatar.oss-cn-wuhan-lr.aliyuncs.com/903c92f279a11371074498d20e48c267.jpg");
        String nickname = "默认用户" + RandomUtil.randomString(6);
        NewUser.setNickname(nickname);
        NewUser.setRole(0);
        NewUser.setStatus(0);

        try{
            userMapper.insertUser(NewUser);
            log.info("新用户注册成功:{}" , NewUser.getEmail());
        }
        catch (Exception e){
            log.error("数据库插入失败:{}", email, e);
            return Result.error(500,"服务器内部错误！");
        }

        RegisterVO registerVO = new RegisterVO();
        BeanUtil.copyProperties(NewUser, registerVO);

        stringRedisTemplate.delete(CacheCodeKey);
        return Result.success("注册成功！请返回重新登录！",registerVO);
    }

    @Override
    public Result LoginByPassword(LoginByPasswordDTO loginByPasswordDTO, HttpServletRequest request) {
        User getUser = userMapper.FindByEmailAndPassword(loginByPasswordDTO.getEmail(), loginByPasswordDTO.getPassword());

        if(getUser == null){
            return Result.error(404,"用户不存在或者密码错误！请重新登录！");
        }

        if(getUser.getStatus() == 1){
            return Result.error(403,"用户已经被封禁，请联系管理员！");
        }

        if(getUser.getIsLogin().equals("Y")){
            return Result.error(400, "用户已登录！");
        }
        String Token = tokenUtils.getToken(getUser.getId().toString(), getUser.getRole().toString());
        getUser.setIsLogin("Y");
        userMapper.LoginUpdate(getUser);
        
        // 添加调试日志
        log.info("登录用户信息 - ID: {}, nickname: {}, avatar: {}", 
                getUser.getId(), getUser.getNickname(), getUser.getAvatar());
        
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(Token);
        BeanUtil.copyProperties(getUser, loginVO);
        // 强制补充avatar，防止BeanUtil丢字段
        loginVO.setAvatar(getUser.getAvatar());
        
        // 添加调试日志
        log.info("返回的登录VO信息 - ID: {}, nickname: {}, avatar: {}", 
                loginVO.getId(), loginVO.getNickname(), loginVO.getAvatar());
        
        return Result.success("登录成功",loginVO);
    }

    @Override
    public Result LoginByCode(LoginByCodeDTO loginByCodeDTO, HttpServletRequest request){
        String email = loginByCodeDTO.getEmail();
        String Code = loginByCodeDTO.getCode();
        String CacheCodeKey = RedisConstant.LOGIN_EMAIL_KEY + email;
        String CacheCode = stringRedisTemplate.opsForValue().get(CacheCodeKey);

        if(CacheCode == null)
        {
            return Result.error(400,"验证码未发送或已过期，请重新获取！");
        }

        if(!Code.equals(CacheCode)){
            return Result.error(400,"验证码错误！");
        }
        User getUser = userMapper.FindByEmail(email);

        if(getUser == null){
            return Result.error(400,"用户不存在，请注册后再使用！");
        }

        if(getUser.getStatus() == 1){
            return Result.error(403,"该账号已经被封禁，请联系管理员！");
        }
        if(getUser.getIsLogin().equals("Y")){
            return Result.error(400, "该用户已登录！");
        }
        getUser.setIsLogin("Y");
        userMapper.LoginUpdate(getUser);
        LoginVO loginVO = new LoginVO();
        String Token = tokenUtils.getToken(getUser.getId().toString(), getUser.getRole().toString());
        loginVO.setToken(Token);
        BeanUtil.copyProperties(getUser, loginVO);
        // 强制补充avatar，防止BeanUtil丢字段
        loginVO.setAvatar(getUser.getAvatar());

        stringRedisTemplate.delete(CacheCodeKey);
        return Result.success("登录成功",loginVO);
    }

    @Override
    public Result UpdateCommonData(UpdateCommonDataDTO updateCommonDataDTO, HttpServletRequest request){
        User updateuser = new User();
        BeanUtil.copyProperties(updateCommonDataDTO, updateuser);
        userMapper.CommonDataUpdate(updateuser);
        UpdateCommonDataVO updateCommonDataVO = new UpdateCommonDataVO();
        User getuser = userMapper.FindCommonData(updateCommonDataDTO.getId());
        BeanUtil.copyProperties(getuser, updateCommonDataVO);
        return Result.success(updateCommonDataVO);
    }

    @Override
    public Result UpdatePassword(UpdatePasswordDTO updatePasswordDTO, HttpServletRequest request){
        User getuser = new User();
        String email = updatePasswordDTO.getEmail();
        String Code = updatePasswordDTO.getCode();

        String CacheCodeKey = RedisConstant.LOGIN_EMAIL_KEY + email;
        String CacheCode = stringRedisTemplate.opsForValue().get(CacheCodeKey);

        if(CacheCode == null)
        {
            return Result.error(400,"验证码未发送或已过期，请重新获取！");
        }

        if(!Code.equals(CacheCode)){
            return Result.error(400,"验证码错误！");
        }

        getuser.setEmail(updatePasswordDTO.getEmail());
        getuser.setPassword(updatePasswordDTO.getNewPassword());
        getuser.setIsLogin("N");
        userMapper.PasswordUpdate(getuser);
        getuser = userMapper.FindByEmail(getuser.getEmail());
        UpdatePasswordVO updatePasswordVO = new UpdatePasswordVO();
        BeanUtil.copyProperties(getuser, updatePasswordVO);

        stringRedisTemplate.delete(CacheCodeKey);
        return Result.success("密码修改成功！请重新登录！", updatePasswordVO);
    }

    @Override
    public Result ResetPassword(ResetPasswordDTO resetPasswordDTO, HttpServletRequest request){
        String email = resetPasswordDTO.getEmail();
        String Code = resetPasswordDTO.getCode();
        String CacheCodeKey = RedisConstant.LOGIN_EMAIL_KEY + email;
        String CacheCode = stringRedisTemplate.opsForValue().get(CacheCodeKey);

        if(CacheCode == null)
        {
            return Result.error(400,"验证码未发送或已过期，请重新获取！");
        }

        if(!Code.equals(CacheCode)){
            return Result.error(400,"验证码错误！");
        }

        User user = new User();

        String NewPassword = "123456aaa";

        user.setEmail(email);
        user.setPassword(NewPassword);
        userMapper.ResetPassword(user);
        ResetPasswordVO resetPasswordVO = new ResetPasswordVO();
        resetPasswordVO.setEmail(email);
        resetPasswordVO.setNewPassword(NewPassword);
        stringRedisTemplate.delete(CacheCodeKey);
        return Result.success("密码已经成功重置为" + NewPassword, resetPasswordVO);
    }

    @Override
    public Result FindDataByID(FindDataByIDDTO findDataByIDDTO, HttpServletRequest request){
        User getuser = userMapper.FindDataByID(findDataByIDDTO.getId());
        if(getuser == null){
            return Result.error(400,"用户不存在！");
        }
        
        // 添加调试日志
        log.info("查询到的用户信息 - ID: {}, nickname: {}, avatar: {}", 
                getuser.getId(), getuser.getNickname(), getuser.getAvatar());
        
        FindDataByIDVO findDataByIDVO = new FindDataByIDVO();
        BeanUtil.copyProperties(getuser, findDataByIDVO);
        // 强制补充avatar，防止BeanUtil丢字段
        findDataByIDVO.setAvatar(getuser.getAvatar());
        
        // 添加调试日志
        log.info("返回的VO信息 - ID: {}, nickname: {}, avatar: {}", 
                findDataByIDVO.getId(), findDataByIDVO.getNickname(), findDataByIDVO.getAvatar());
        
        return Result.success("查找成功！", findDataByIDVO);
    }

    @Override
    public Result UpdateAvatar(UpdateAvatarDTO updateAvatarDTO, HttpServletRequest request){
        MultipartFile NewAvatarFile = updateAvatarDTO.getAvatarFile();
        Integer id = updateAvatarDTO.getId();
        User user = userMapper.FindDataByID(id);
        if(user == null){
            return Result.error(404,"用户不存在！");
        }

        if(NewAvatarFile.getSize() > 2 * 1024 * 1024){
            return Result.error(400,"上传文件不得大于2M！");
        }

        try{
            String oldAvatarUrl = user.getAvatar();
            if(StringUtils.isNotEmpty(oldAvatarUrl) && oldAvatarUrl.contains("oss")
            && !oldAvatarUrl.equals("https://classtopia-avatar.oss-cn-wuhan-lr.aliyuncs.com/903c92f279a11371074498d20e48c267.jpg")){
                try{
                    aliOSSUtils.DeleteFile(oldAvatarUrl);
                }
                catch (Exception e){
                    log.warn("删除旧头像失败:{}" , oldAvatarUrl, e);
                }
            }

            String newAvatarUrl = aliOSSUtils.upload(NewAvatarFile, "classtopia-avatar");

            userMapper.UpdateAvatar(newAvatarUrl, Long.valueOf(id));

            UpdateAvatarVO updateAvatarVO = new UpdateAvatarVO();
            updateAvatarVO.setAvatarURL(newAvatarUrl);
            updateAvatarVO.setId(id);

            return Result.success("头像上传成功！", updateAvatarVO);

        }
        catch (Exception e){
            log.error("头像上传失败:{}", id, e);
            return Result.error(500,"头像上传失败");
        }
    }

   @Override
    public Result Logout(Long id, HttpServletRequest request){
        User getuser = userMapper.FindDataByID(Math.toIntExact(id));
        if(getuser == null){
            return Result.error(404, "用户不存在！");
        }
        if("N".equals(getuser.getIsLogin())){
            return Result.error(403, "用户未登录！");
        }
        getuser.setIsLogin("N");
        userMapper.LoginUpdate(getuser);
        return Result.success("用户已退出登录！");
    }

    @Override
    public Result SendVerificationCode(String email, HttpServletRequest request)
    {
        if(!RegexUtils.isEmail(email)) return Result.error(400,"邮箱格式不正确");

        String CountKey = RedisConstant.LOGIN_EMAIL_LIMIT_KEY + email;
        Boolean SetSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
                CountKey, "1", Duration.ofSeconds(LIMIT_SECONDS)
        );

        if(Boolean.FALSE.equals(SetSuccess)) return Result.error(400, "请求过于频繁，请稍候再试！");
        String Code = RandomUtil.randomNumbers(6);
        log.debug("成功生成验证码，邮箱{}，验证码{}", email, Code);

        try{
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(email);
            helper.setSubject("ClassTopia 邮箱验证码");

            String content = "<div style=\"font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #eee; border-radius: 5px;\">" +
                    "<h2 style=\"color: #333;\">您好！</h2>" +
                    "<p>感谢您使用ClassTopia平台,您的验证码是：</p>" +
                    "<div style=\"background-color: #f5f5f5; padding: 10px; text-align: center; font-size: 24px; font-weight: bold; letter-spacing: 5px; margin: 20px 0;\">" +
                    Code +
                    "</div>" +
                    "<p>此验证码将在10分钟内有效。</p>" +
                    "<p>如果您没有请求此验证码，请忽略此邮件。</p>" +
                    "<p style=\"margin-top: 30px; font-size: 12px; color: #888;\">" +
                    "这是一封自动生成的邮件，请勿直接回复。" +
                    "</p></div>";

            helper.setText(content, true);
            mailSender.send(message);
        }
        catch (Exception e){
            return Result.error(400,"邮件发送失败！");
        }

        stringRedisTemplate.opsForValue().set(LOGIN_EMAIL_KEY + email, Code, Duration.ofMinutes(CODE_EXPIRE_MINUTES));
        return Result.success("验证码发送成功！",200);
    }

    @Override
    public List<Long> getAllUserIds() {
        return userMapper.selectAllUserIds();
    }
}
